using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Data;

namespace MyClever.Lib
{    
    public enum PluginDevStatus
    {
        Prototype,
        Development,
        Production
    }

    public enum ProgrammingLanguage
    {
        None,
        CSharp,
        Python
    }    

    public enum PluginProperty
    {
        // only get
        Maintainer,
        Name,
        Version,
        // get and set
        Description,
        Author,
        Copyright,
        Credits,
        License,
        Email,
        Tags,
        Status,
        Language
    }
    
    [Flags]
    public enum Direction
    {
        Input = 1,
        Output = 2,
        Logging = 4,
        All = Input | Output | Logging
    }
    
    [AttributeUsage(AttributeTargets.Enum)]
    public class PackageAttribute : Attribute
    {
        private Direction direction;
        private string description;

        public Direction Direction
        {
            get { return this.direction; }
        }

        public string Description
        {
            get { return this.description; }
        }

        public PackageAttribute(Direction packageDirection, string packageDescription)
        {
            this.direction = packageDirection;
            this.description = packageDescription;
        }
    }

    [AttributeUsage(AttributeTargets.Field)]
    public class ColumnAttribute : Attribute
    {
        private Type type;
        private string description;
        private string validation;
        private string defaultValue;

        public Type ValueType
        {
            get { return this.type; }
        }

        public string Description
        {
            get { return this.description; }
        }

        public string Validation
        {
            get { return this.validation; }
            set { this.validation = value; }
        }

        public string DefaultValue
        {
            get { return this.defaultValue; }
            set 
            {
                // todo: assert springt nicht an!
                Debug.Assert(null != Convert.ChangeType(value, this.type));
                this.defaultValue = value; 
            }
        }

        public ColumnAttribute(Type valueType, string columnDescription)
        {
            this.type = valueType;
            this.description = columnDescription;
        }
    }

    [AttributeUsage(AttributeTargets.Constructor)]
    public class PluginAttribute : Attribute
    {
        public Dictionary<PluginProperty, object> attributes = new Dictionary<PluginProperty, object>();

        /// <summary>
        /// Gets the description of the plugin.
        /// </summary>
        /// <value>The description of the plugin.
        /// Should contain one ore more sentences to describe for what the plugin is good for.</value>
        public string Description
        {
            get { return (string)this.attributes[PluginProperty.Description]; }
        }

        /// <summary>
        /// Gets the author of the plugin.
        /// </summary>
        /// <value>The author of the plugin. For example your name or your company-name.</value>
        public string Author
        {
            get { return (string)this.attributes[PluginProperty.Author]; }
            set { this.attributes[PluginProperty.Author] = value; }
        }

        public PluginDevStatus Status
        {
            get { return (PluginDevStatus)this.attributes[PluginProperty.Status]; }
        }

        public string License
        {
            get { return (string)this.attributes[PluginProperty.License]; }
            set { this.attributes[PluginProperty.License] = value; } 
        }

        /// <summary>
        /// Gets the version of the plugin.
        /// </summary>
        /// <value>Defines the version of this plugin, using the following syntax: major.minor.build</value>
        public string Version
        {
            get { return (string)this.attributes[PluginProperty.Version]; } 
        }
        
        public string Copyright
        {
            get { return (string)this.attributes[PluginProperty.Copyright]; }
            set { this.attributes[PluginProperty.Copyright] = value; }
        }
        
        /// <summary>
        /// Differs from author in that credits includes people who reported bug fixes, made suggestions, etc. but did not actually write the code.
        /// </summary>
        /// <value>The credits.</value>
        public string Credits
        {
            get { return (string)this.attributes[PluginProperty.Credits]; }
            set { this.attributes[PluginProperty.Credits] = value; }
        }

        /// <summary>
        /// Should be the person who will fix bugs and make improvements
        /// </summary>
        /// <value>The maintainer.</value>
        public string Maintainer
        {
            get { return (string)this.attributes[PluginProperty.Maintainer]; }
        }

        public string Email
        {
            get { return (string)this.attributes[PluginProperty.Email]; }
            set { this.attributes[PluginProperty.Email] = value; }
        }

        /// <summary>
        /// Gets some keywords which describes the plugin.
        /// </summary>
        /// <value>Comma seperated keywords which describe this plugin. 
        /// By using other words as in the <see cref="Description"/> you can help other users to find this plugin on the "MyCleverFriend"-website.</value>
        public string Tags
        {
            get { return (string)this.attributes[PluginProperty.Tags]; }
            set { this.attributes[PluginProperty.Tags] = value; }
        }

        public PluginAttribute(PluginDevStatus status, string description)
        {
            this.attributes[PluginProperty.Status] = status;
            this.attributes[PluginProperty.Description] = description;
        }
    }

    /// <summary>
    /// This is a very simple remotable class, which transfers all package definitions between two appDomains.
    /// </summary>
    [Serializable()]
    public class PackageColumnDefinition
    {
        public string name;
        public string valueType;
        public object defaultValue;
        public Dictionary<MissionPluginPackageColumn.ExtendedPropertiesKey, object> extendedProperties;

        public PackageColumnDefinition(string columnName, Type valueType, object defaultValue)
            : this(columnName, valueType)
        {
            this.defaultValue = defaultValue;
        }

        public PackageColumnDefinition(string columnName, Type valueType)
        {
            this.name = columnName;
            this.valueType = valueType.ToString();

            this.extendedProperties = new Dictionary<MissionPluginPackageColumn.ExtendedPropertiesKey, object>();
        }
    }

    /// <summary>
    /// This is a very simple remotable class, which transfers all package definitions between two appDomains.
    /// </summary>
    [Serializable()]
    public class PackageDefinition
    {
        public string name;
        public Direction direction;
        public string description;
        public bool isSoftPackage;
        public List<PackageColumnDefinition> columnDefinitions;
        public List<object[]> rows;

        public PackageDefinition(string packageName, Direction packageDirection, string packageDescription, bool isSoftPackage)
        {
            this.name = packageName;
            this.direction = packageDirection;
            this.description = packageDescription;
            this.isSoftPackage = isSoftPackage;

            this.columnDefinitions = new List<PackageColumnDefinition>();
            this.rows = new List<object[]>();
        }
    }

    public enum DockOrientation
    {
        None,
        Left,
        Right,
        Down
    }

    public class RelativePluginPosition
    {
        public DockOrientation orientation;
        public int basedOnPluginID;

        public RelativePluginPosition(DockOrientation orientation, int basedOnPluginID)
        {
            this.orientation = orientation;
            this.basedOnPluginID = basedOnPluginID;
        }

        public bool IsValid()
        {
            return (DockOrientation.None != this.orientation || this.basedOnPluginID >= 0);
        }
    }




    public class PackageReference
    {
        protected int pluginID;
        protected string packageName;

        public PackageReference(int fromPluginID, string fromPackageName)
        {
            Debug.Assert(fromPluginID >= 0);
            Debug.Assert(false == String.IsNullOrEmpty(fromPackageName));
            
            this.pluginID = fromPluginID;
            this.packageName = fromPackageName;
        }

        public int PluginID
        {
            get
            {
                return this.pluginID;
            }
        }

        public string PackageName
        {
            get
            {
                return this.packageName;
            }
        }
    }

    public class PackageColumnReference : PackageReference
    {
        protected string columnName;

        public PackageColumnReference(int fromPluginID, string fromPackageName, string fromColumnName) 
            : base(fromPluginID, fromPackageName)
        {
            Debug.Assert(false == String.IsNullOrEmpty(fromColumnName));

            this.columnName = fromColumnName;
        }

        public string ColumnName
        {
            get
            {
                return this.columnName;
            }
        }
    }

    [Serializable()]
    public class PackageCellReference
    {
        protected int loopID;
        protected string columnName;

        public PackageCellReference(int fromLoopID, string fromColumnName)
        {
            Debug.Assert(fromLoopID >= 0);
            Debug.Assert(false == String.IsNullOrEmpty(fromColumnName));

            this.loopID = fromLoopID;
            this.columnName = fromColumnName;
        }

        public int LoopID
        {
            get
            {
                return this.loopID;
            }
        }

        public string ColumnName
        {
            get
            {
                return this.columnName;
            }
        }
    }

}
